package com.example.blog.config;

import com.alibaba.fastjson2.JSONObject;
import com.example.blog.domain.LoginUser;
import com.example.blog.domain.Response;
import com.example.blog.domain.Users;
import com.example.blog.note.NoToken;
import com.example.blog.utils.JwtUtils;
import com.example.blog.utils.RedisStorage;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.lang.reflect.Method;

// 自定义拦截器

/**
 * 部分的请求都应该携带Jwt进行访问
 */
@Component
@Slf4j
public class JwtRequestFilter implements HandlerInterceptor {
    @Autowired
    private RedisStorage redisStorage;
    // Controller执行之前进行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取传递过来的token
        String Authorization = request.getHeader("token");
        //设置返回值格式为 json
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json,charset=utf-8");
        PrintWriter out; // 返回内容传递对象
        //注解的判断
        HandlerMethod handlerMethod = null;
        try {
         handlerMethod = (HandlerMethod) handler;
        }catch (Exception e){
           if(e instanceof ClassCastException){
               return false;
           }
        }
        //获取该请求的方法,即请求所对应的方法
        Method method = handlerMethod.getMethod();
        //检查该方法有没有自定义的NoToken注解
        if (method.isAnnotationPresent(NoToken.class)) {
            // 从该方法上获取该注解
            NoToken jwtToken = method.getAnnotation(NoToken.class);
            // 自定义注解的方法，默认值为true,为true 则表明不需要认证Jwt
            if (jwtToken.required())
                return true; //放行
        }

        //解析token
        Claims claims = JwtUtils.checkToken(Authorization);
        //准备返回错误的JSON数据
        JSONObject res = new JSONObject();
        //如果传递的token为空，或者无效 返回错误信息
            if (Authorization == null || claims==null) {
                res.put("code", 401);
                res.put("msg", "token过期或无效");
                res.put("data", null);
                //将响应数据返回前端
                out = response.getWriter();
                out.append(res.toString());
                // 停止前端请求
                return false;
            }
            //解析token转换为需要的long类型uid
            long uid = Long.parseLong(String.valueOf(claims.get("uid")));
        //检查token是否唯一，有无重复登录
       if( !redisStorage.checkLogin(new LoginUser(uid,Authorization))){
           res.put("code", Response.Remote);
           res.put("msg", "你的账户已在另一处登录！");
           res.put("data", null);
           //将响应数据返回前端
           out = response.getWriter();
           out.append(res.toString());
           return false;
       }

        return true; // 放行
    }


    // Controller执行完毕后进行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    // Controller执行完毕后进行  一般用于资源的处理工作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
